#ifndef APPLICATION_WINDOW_WRAPPER_H
#define APPLICATION_WINDOW_WRAPPER_H

#include <string>
#include "engine/result_codes.h"
#include "engine/application_state.h"
namespace engine {

class WindowProperties {
public:    
    WindowProperties(): position_x_(0), position_y_(0) {}
    inline const std::string & GetTitle() const { return title_; }
    inline const long & GetWidth() const { return width_; }
    inline const long & GetHeight() const { return height_; }
    inline const long & GetPositionX() const { return position_x_; }
    inline const long & GetPositionY() const { return position_y_; }
    inline void GetPosition(long & position_x, long & position_y) const {
        position_x = position_x_;
        position_y = position_y_;
    }
     
    inline void SetTitle(const std::string &title) { 
        title_ = title; 
    }
    inline void SetSize(const long &width, const long &height) {
        width_ = width;
        height_ = height;
    }

    inline void SetPosition(const long &position_x, const long &position_y) {
        position_x_ = position_x;
        position_y_ = position_y;    
    }
    inline void Move(const long &dx, const long &dy) {
        position_x_ += dx;
        position_y_ += dy;        
    }
 
private:
    long position_x_, position_y_;
    long width_, height_;
    std::string title_;
};

class WindowWrapper {
public:
    WindowWrapper(ApplicationState & state) : state_(state) {}
    virtual ~WindowWrapper() {}
    virtual int DoEvents() {return base::OK_OK; }

    int Initialize() {
        return Initialize(properties_);
    }
    int Initialize(const WindowProperties & params) {
        properties_ = params;        
        state_.set(APP_INITIALIZING, true);
        int result = OnInitialize();
        state_.set(APP_INITIALIZING, false);
        
        if(result >= 0)
            state_.set(APP_INITIALIZED, true);
        
        return result;
    }

    int Close() {
        state_.set(APP_CLOSED, true);
        return OnClose();
    }

    int Minimize() {
        if(!state_.test(APP_INITIALIZED)) {
            state_.set(APP_MINIMIZED, true);
            return base::OK_OK;
        } else if(!state_.test(APP_MINIMIZED)) {
            state_.set(APP_MINIMIZED, true);  
            return OnMinimize();
        } else return base::OK_FALSE;
    }

    int Maximize() {
        if(!state_.test(APP_INITIALIZED)) {
            state_.set(APP_MAXIMIZED, true);
            return base::OK_OK;
        } else if(!state_.test(APP_MAXIMIZED)) {
            state_.set(APP_MAXIMIZED, true);  
            return OnMaximize();
        } else return base::OK_FALSE;
    }

    int ToFullscreen() { 
        if(!state_.test(APP_INITIALIZED)) {
            state_.set(APP_FULLSCREEN, true);
            return base::OK_OK;
        } else if(!state_.test(APP_FULLSCREEN)) {
            state_.set(APP_FULLSCREEN, true);  
            return OnToFullscreen();
        } else return base::OK_FALSE;
    }
    int ToWindowed() {
        if(!state_.test(APP_INITIALIZED)) {
            state_.set(APP_FULLSCREEN, false);
            return base::OK_OK;
        } else if(state_.test(APP_FULLSCREEN)) {
            state_.set(APP_FULLSCREEN, false);  
            return OnToWindowed();
        } else return base::OK_FALSE;
    }

    int Show() {
        if(!state_.test(APP_INITIALIZED)) {
            state_.set(APP_HIDDEN, false);
            return base::OK_OK;
        } else if(state_.test(APP_HIDDEN)) {
            state_.set(APP_HIDDEN, false);  
            return OnShow();
        } else return base::OK_FALSE;
    }

    int Hide() {
        if(!state_.test(APP_INITIALIZED)) {
            state_.set(APP_HIDDEN, true);
            return base::OK_OK;
        } else if(state_.test(APP_HIDDEN)) {
            state_.set(APP_HIDDEN, true);  
            return OnHide();
        } else return base::OK_FALSE;
    }

    int ReleaseResources() {
        state_.set(engine::APP_HAS_FOCUS, true);
        return OnReleaseResources();
    }
    int CaptureResources() {
        state_.set(engine::APP_HAS_FOCUS, true);
        return OnCaptureResources();
    }


    int Resize(const long & width, const long & height) {
        properties_.SetSize(width, height);

        if(state_.test(APP_INITIALIZED)) 
            return OnResize(width, height);
        else return base::OK_OK;   
        
    }
    int Move(const long & dx, const long &dy) {
        properties_.Move(dx, dy);
        if(state_.test(APP_INITIALIZED)) 
            return OnMove(dx, dy);
        else return base::OK_OK;   
    }

    int MoveTo(const long &position_x, const long &position_y) {
        properties_.SetPosition(position_x, position_y);
        if(state_.test(APP_INITIALIZED)) {
            int dx = position_x - properties_.GetPositionX();
            int dy = position_y - properties_.GetPositionY();
            return OnMove(dx, dy);
        } else return base::OK_OK;   
    }

    void SetTitle(const std::string &title) {properties_.SetTitle(title);}
    inline const ApplicationState & GetApplicationState() const {return state_;}
protected:
    WindowProperties properties_;
    ApplicationState & state_;
    virtual int OnInitialize()=0;
    virtual int OnClose()= 0;
    virtual int OnMinimize(){return base::OK_OK; }
    virtual int OnMaximize(){return base::OK_OK; }
    virtual int OnShow(){return base::OK_OK; }
    virtual int OnHide(){return base::OK_OK; }
    virtual int OnToFullscreen() {return base::OK_OK; }
    virtual int OnToWindowed() {return base::OK_OK; }
    virtual int OnReleaseResources(){return base::OK_OK; }
    virtual int OnCaptureResources(){return base::OK_OK; }
    
    virtual int OnResize(const long &, const long & height) = 0;
    virtual int OnMove(const long &dx, const long & dy){return base::OK_OK; }
};

}
#endif //ENGINE_WINDOW_WRAPPER_H